#include <vector>
#include <stack>
#include <list>

#ifndef FUNCTION_H
#define FUNCTION_H

class Function 
{

public:
    const char* const name;             // The name of the function
    std::vector<Function*> dependents;  // List of functions that depend on this one
    int dependencies;                   // Number of function on which it still depends
    int time;                           // Time in milliseconds
    bool called;                        // Boolean to indicate if it has been called

    Function (const char* n) : name (n), called (false), dependencies (0), time (0) {}
    Function (const char* n, int t) : name (n), called (false), dependencies (0), time (t) {}
    ~Function() { /*delete name;*/}    

    inline bool IsReady() { return dependencies == 0; }  
    inline bool HasBeenCalled() { return called; }

    bool AddDependent (Function* f);
    bool ContainsDependent (Function* f);
};


class Processor 
{
    int time;
    std::list<Function*> assignments; 
    
public:
    Processor() : time (0) {}
    
    inline int GetExecTime() { return time; }
    inline void AddAssignment (Function* f, int t) { time += t - time; assignments.push_back (f); }
    inline void Clear() { time = 0; assignments.clear(); }
    void Print();
};


class CallGraph 
{
    std::list<Function*> graph;
    
public:
    CallGraph() {}
    ~CallGraph();            
    
    class Enumeration {
        std::list<Function*> calls;        
        std::stack<std::list<Function*>* > choices;
        std::stack<std::list<Function*>::iterator> indices;                        
        
    public:
        Enumeration (Function* root);
        Enumeration (std::list<Function*>& roots);
        ~Enumeration();
        
        bool HasMoreElements();
        std::list<Function*>& NextElement();
    };
    
    inline void AddNode (Function* f) { graph.push_back (f); }
    Enumeration GetEnumeration();
    void SetRandomTime();
    
    void Print();
    
    Processor* Schedule (int n);
};

#endif // FUNCTION_H
